#include "usart.h"
#include "command.h"
#include "c_boot.h"

__attribute__ ((aligned(4)))     uint8_t USARTTXFIFO[USARTTXLENGTH];
__attribute__ ((aligned(4)))     uint8_t USARTRXFIFO[USARTRXLENGTH];

static void dma_Init(void){

    DMA_InitTypeDef DMA_InitStructure={0};

    RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE );

    DMA_DeInit(USART_TX_CH);
    DMA_DeInit(USART_RX_CH);

    _core_memset(USARTTXFIFO ,0x00 ,USARTTXLENGTH);
    _core_memset(USARTRXFIFO ,0x00 ,USARTRXLENGTH);

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DATAR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USARTTXFIFO;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = 0;

    DMA_Init( USART_TX_CH, &DMA_InitStructure );

    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DATAR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USARTRXFIFO;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = USARTRXLENGTH;

    DMA_Init( USART_RX_CH, &DMA_InitStructure );

}

void USART1_Config(void){

    GPIO_InitTypeDef  GPIO_InitStructure  = {0};
    USART_InitTypeDef USART_InitStructure = {0};
    NVIC_InitTypeDef  NVIC_InitStructure  = {0};

    dma_Init();

    DMA_Cmd(USART_RX_CH, ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO , ENABLE);

    /* USART1 TX-->A.9   RX-->A.10 */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate            = 921600U;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Tx | USART_Mode_Rx;

    USART_Init(USART1, &USART_InitStructure);
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel                   = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    NVIC_EnableIRQ(USART1_IRQn);

    USART_Cmd(USART1, ENABLE);

    USART_DMACmd( USART1 , USART_DMAReq_Tx|USART_DMAReq_Rx , ENABLE);

}


void USART1_Transmit(uint8_t* pDATA ,uint16_t  Length){

    for(uint16_t i = 0;i < Length;i ++){
        while(USART_GetFlagStatus(USART1 ,USART_FLAG_TC) == RESET)
        {

        }
        USART_ClearFlag(USART1 ,USART_FLAG_TC);
        USART_SendData(USART1 ,pDATA[i]);
    }
}

void USART_Transmit_DMA(uint8_t *pData, uint16_t Size)
{
//    DMA_Cmd(USART_TX_CH, ENABLE);
    while(USART_TX_CH->CNTR)
    {
        ;
    }

    DMA_Cmd(USART_TX_CH, DISABLE);

    USART_TX_CH->MADDR = (uint32_t)pData;
    USART_TX_CH->CNTR = Size;

    DMA_Cmd(USART_TX_CH, ENABLE);

}

void command_apply(ModbusType*  Mbus)
{


}

/*********************************************************************
 * @fn      USART1_IRQHandler
 *
 * @brief   This function handles USART1 global interrupt request.
 *
 * @return  none
 */
void USART1_IRQHandler(void)           __attribute__((interrupt("WCH-Interrupt-fast")));
void USART1_IRQHandler(void)
{
    if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
    {

        DMA_Cmd(USART_RX_CH, DISABLE);

        USART_RX_CH->CNTR = USARTRXLENGTH;
        DMA_Cmd(USART_RX_CH, ENABLE);

        USART_ReceiveData(USART1);

    }
}
